﻿using System;
using System.Linq;
using System.Web.Mvc;
using System.Web.Security;
using ContactManagement.Models;
using ContactMvc4TB.Helpers.HelperClasses;
using ContactMvc4TB.Helpers.MailManagement;
using EFDataModel;
using EFDataModel.Enums;
using Microsoft.Web.Helpers;

namespace ContactManagement.Controllers
{
    public class AccountController : Controller
    {
        /// <summary>
        /// Anzeigen der Loginseite 
        /// GET: /Account/Login
        /// </summary>
        /// <returns></returns>
        public ActionResult Login()
        {
            return View();
        }

        /// <summary>
        /// Loginvorgang, es wird das Loginmodel zurückgegeben
        /// POST: /Account/Login
        /// </summary>
        /// <param name="model">Das LoginModel mit Username und Passwort</param>
        /// <param name="returnUrl">Die URL die aufgerufen wurde und die nagezeigt werden soll</param>
        [HttpPost]
        public ActionResult Login(LogOnModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                string errorMessage = string.Empty;
                //Prüfen ob der aktuelle User gefunden werden kann und sich mit dem PW einloggen kann
                EFAuthentication efAuthentication = EFAuthentication.LoginUser(model.UserName, model.Password, CurrentHttpContext.GetDataModel(), ref errorMessage);
                //Der Account muss ebenfalls aktiv sein, damit sich ein User anmelden kann
                if (efAuthentication != null && efAuthentication.IsActiveUser)
                {
                    //Den im Cookie die UserId setzen und ob der User angemeldet bleiben soll oder nicht.
                    FormsAuthentication.SetAuthCookie(efAuthentication.ID.ToString(), model.RememberMe);
                    //Prüfen ob auf eine bestimmt URL weitergeleitet werden soll.
                    if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/") && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
                    {
                        return Redirect(returnUrl);
                    }
                    else
                    {
                        //Auf die Arbeitszeiterfassung verweisen.
                        return RedirectToAction(EActionWorktime.WorktimeIndex.ToString(), EControllers.Worktime.ToString());
                    }
                }
                else
                {
                    //Fehlermeldungen die bei einem Nicht erfolgreichen Loginvorgang auftreten können hier anzeigen.
                    ModelState.AddModelError("", errorMessage);
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

        /// <summary>
        /// Ausloggen des aktuellen Users
        /// GET: /Account/LogOff
        /// </summary>
        public ActionResult LogOff()
        {
            FormsAuthentication.SignOut();
            //Direkt auf die Loginseite verweisen, nachdem sich der User ausgeloggt hat.
            return RedirectToAction(EActionAccount.Login.ToString(), EControllers.Account.ToString());
        }

        /// <summary>
        /// Auf die Registrierungsseite verweisen
        /// GET: /Account/Register
        /// </summary>
        /// <returns></returns>
        public ActionResult Register()
        {
            //Es muss eine Instanz vom Model angelegt werden, da sonst im View die Variable "Model" Null ist und die Liste mit der Anrede nicht angezeigt werden kann
            RegisterModel registerModel = new RegisterModel();
            return View(registerModel);
        }

        /// <summary>
        /// Registrieren der Userdaten
        /// POST: /Account/Register
        /// </summary>
        /// <param name="model">Userdaten die registriert werden sollen</param>
        [HttpPost]
        public ActionResult Register(RegisterModel model)
        {
            if (ReCaptcha.Validate())
            {
                if (ModelState.IsValid)
                {
                    try
                    {
                        // Anlegen des neuen Users in der Datenbank
                        EFUser efUser = new EFUser();
                        efUser.Firstname = model.Firstname;
                        efUser.EditDate = DateTime.Now;
                        efUser.CreationDate = DateTime.Now;
                        efUser.UserType = EUserTypes.Registered;
                        efUser.Lastname = model.Lastname;
                        efUser.LoginEmail = model.UserName;
                        efUser.Module = EFModules.Member;
                        //Aufpassen mit der Kategorie, gibt kein Enum, da diese frei angelegt werden können
                        efUser.UserCategory = (from eUserCategory in CurrentHttpContext.GetDataModel().EFCategoryMenge.OfType<UserCategory>() where eUserCategory.Name == "Mitarbeiter" select eUserCategory).FirstOrDefault();
                        //Für mehr sicherheit könnte man hier noch prüfen ob die Id auch wirklich existiert vom Titel
                        efUser.UserTitleID = int.Parse(model.UserTitle);
                        //Pw wird direkt gehasht
                        efUser.SetPassword(model.Password);
                        CurrentHttpContext.GetDataModel().EFBaseMenge.Add(efUser);
                        CurrentHttpContext.GetDataModel().SaveChanges();

                        if (efUser.ID != 0)
                        {
                            FormsAuthentication.SetAuthCookie(efUser.ID.ToString(), false);
                            CustomMessage.CurrentMessage(this).AddMessage(GlobalResources.SystemMessages.RegistrationSuccessFullRESX, MessageTypes.ok);
                            return RedirectToAction(EActionHome.Index.ToString(), EControllers.Home.ToString());
                        }
                        else
                        {
                            ModelState.AddModelError("",GlobalResources.SystemMessages.UserCreationErrorRESX);
                        }
                    }
                    catch (Exception ex)
                    {
                        EFDebugging.Debugging.WriteLog("Registrierungsfehler: ", ex);
                        ModelState.AddModelError("",GlobalResources.SystemMessages.UserCreationErrorRESX);
                    }
                }
            }
            else
            {
                ModelState.AddModelError("",GlobalResources.SystemMessages.CaptchaWasWrongRESX);
            }
            // If we got this far, something failed, redisplay form
            return View(model);
        }

        /// <summary>
        /// Webseite Anzeigen auf der das Passwort zurück gesetzt werden kann.
        /// </summary>
        /// <returns></returns>
        public ActionResult ForgottenPassword()
        {
            ForgottenPasswordModel forgotPasswordModel = new ForgottenPasswordModel();
            return View(forgotPasswordModel);
        }

        /// <summary>
        /// Post für das Formular wenn das PW zurück gesetzt werden soll
        /// </summary>
        /// <param name="model">Ausgefülltes Model</param>
        /// <returns></returns>
        [HttpPost]
        public ActionResult ForgottenPassword(ForgottenPasswordModel model)
        {
            if (ModelState.IsValid)
            {
                //Versenden der Mail mit dem Hash, das ein Neues PW angefordert wurde. Erst wenn der User auf den Link in der EMail 
                //Klickt wird ein View auf der Webseite aufgerufen und es wird ein Neues Passwort erstellt und dann erst dem User Per Mail gesendet.

                //Laden des passenden Users zur EMailadresse, kann nicht Null sein da dies bereits in den Attributen überprüft wurde!
                EFUser efUser = EFUser.GetEFUserByEmail(model.UserName, CurrentHttpContext.GetDataModel());
                PasswordRecoveryMail passwordRecoveryMail = new PasswordRecoveryMail(this);
                if (passwordRecoveryMail.InitPasswordRecovery(efUser))
                {
                    return RedirectToAction(EActionAccount.ForgottenPasswordSuccess.ToString());
                }
                else
                {
                    //Es ist ein Fehler aufgetreten, der User soll es zu einem Späteren Zeitpunkt noch einmal versuchen
                    ModelState.AddModelError("",GlobalResources.SystemMessages.ErrorPleaseTryAgainLaterRESX);
                }
            }

            return View(model);
        }

        /// <summary>
        /// Wenn der Wiederherstellungsvorgang erfolgreich gestartet werden konnte wird diese Seite angezeigt.
        /// Inkl. einer kurzen erläuterung wie der Vorgang abläuft.
        /// </summary>
        public ActionResult ForgottenPasswordSuccess()
        {
            return View();
        }

        /// <summary>
        /// Initialisiert das erstellen eines neuen Passwortes
        /// </summary>
        /// <param name="id">UserId für die ein neues Passwort angefordert wurde</param>
        /// <param name="hash">der Hash der benötigt wird als Kontrolle für den User</param>
        public ActionResult NewPasswordSend(int id, string hash)
        {
            PasswordRecoveryMail passwordRecoveryMail = new PasswordRecoveryMail(this);
            passwordRecoveryMail.SetNewPassword(id, hash);
            return View();
        }

        /// <summary>
        /// Validierungsfunktion für den Usernamen, der per AJAX Call aufgerufen wird, wenn über dem jeweiligen Property das Attribut Remote gesetzt wurde
        /// http://www.devtrends.co.uk/blog/the-complete-guide-to-validation-in-asp.net-mvc-3-part-1
        /// </summary>
        /// <param name="userName">Der Username der überprüft werden soll, ob dieser bereits existiert.</param>
        /// <returns>JSON->True/False</returns>
        //[OutputCache(Location = OutputCacheLocation.None, NoStore = true)]
        [HttpGet]
        public virtual JsonResult ValidateUserName(string userName)
        {
            //Gibt dem Ajax aufruf zurück ob der User bereits existiert oder nicht, WICHTIG ist JsonRequestBehavior.AllowGet, sonst wird der AJAX Call nicht verarbeitet.
            return Json(!EFUser.CheckUserExists(userName, CurrentHttpContext.GetDataModel()), JsonRequestBehavior.AllowGet);
        }
    }
}
